package com.tiny.tinyweb.core.dao.xaccess;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;

/**
 * 基于{@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport}
 * 的JDBC操作基类，执行调用者指定的SQL语句（通常是DDL语句）或存储过程。
 * @see {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport}
 * @author wxiaobin
 */
public class JdbcExecute {
    /**
     * JDBC支持对象。
     */
    private NamedParameterJdbcDaoSupport jdbcDaoSupport;

    /**
     * 设置JDBC支持对象。
     * @param jdbcDaoSupport JDBC支持对象的值
     */
    public void setJdbcDaoSupport(NamedParameterJdbcDaoSupport jdbcDaoSupport) {
        this.jdbcDaoSupport = jdbcDaoSupport;
    }

    /**
     * 使用{@link org.springframework.jdbc.core.JdbcTemplate}执行SQL语句（通常是DDL语句）。
     * @param sql SQL语句
     */
    public void jdbcExecute(String sql) {
        this.jdbcDaoSupport.getJdbcTemplate().execute(sql);
    }

    /**
     * 使用{@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
     * 执行SQL语句，并返回执行结果。
     * @param sql SQL语句
     * @param params SQL语句的执行参数
     * @return 执行结果（成功或失败）
     */
    public Boolean jdbcExecute(String sql, Map<String, Object> params) {
        return (Boolean) this.jdbcDaoSupport.getNamedParameterJdbcTemplate().execute(
                sql, params, new PreparedStatementCallback<Object>() {
                    @Override
                    public Object doInPreparedStatement(PreparedStatement ps)
                            throws SQLException, DataAccessException {
                        return ps.execute();
                    }
                });
    }

    /**
     * 使用{@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
     * 执行SQL查询语句，并返回执行结果。
     * @param sql SQL语句
     * @param params SQL语句的执行参数
     * @return 执行结果（结果集）
     */
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> jdbcExecuteQuery(String sql, Map<String, Object> params) {
        return (List<Map<String, Object>>) this.jdbcDaoSupport.getNamedParameterJdbcTemplate().execute(
        		sql, params, new PreparedStatementCallback<Object>() {
        			@Override
                    public Object doInPreparedStatement(PreparedStatement ps)
                            throws SQLException, DataAccessException {
        			    ResultSet rs = ps.executeQuery();
        			    ResultSetMetaData md = rs.getMetaData();
        			    List<Map<String, Object>> resultList = new ArrayList<Map<String,Object>>();
        			    while (rs.next()) {
        			        Map<String,Object> row = new HashMap<String, Object>();
        			        for (int i = 1; i <= md.getColumnCount(); i++) {
        			            row.put(md.getColumnName(i), rs.getObject(i));
        			        }
        			        resultList.add(row);
        			    }
        			    return resultList;
                    }
				});
    }

    /**
     * 使用{@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
     * 执行SQL查询语句，并返回执行结果。
     * @param sql SQL语句
     * @return 执行结果（结果集）
     */
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> jdbcExecuteQuery(String sql) {
        return (List<Map<String, Object>>) this.jdbcDaoSupport.getNamedParameterJdbcTemplate().execute(
        		sql, new PreparedStatementCallback<Object>() {
        			@Override
                    public Object doInPreparedStatement(PreparedStatement ps)
                            throws SQLException, DataAccessException {
        			    ResultSet rs = ps.executeQuery();
                        ResultSetMetaData md = rs.getMetaData();
                        List<Map<String, Object>> resultList = new ArrayList<Map<String,Object>>();
                        while (rs.next()) {
                            Map<String,Object> row = new HashMap<String, Object>();
                            for (int i = 1; i <= md.getColumnCount(); i++) {
                                row.put(md.getColumnName(i), rs.getObject(i));
                            }
                            resultList.add(row);
                        }
                        return resultList;
                    }
				});
    }
}
